package mymongo

import (
	"mygo/mystruct"
	"fmt"
	"context"
	"reflect"
	"strings"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
)


/* =================================================================================
   API表操作
*/
func (api Collections) Check(field, value string) (*mystruct.Retdate, bson.M) {
	results := &mystruct.Retdate{"api-check", mystruct.MyCodeOk, "succeed"}

	ret := api.FindOne(context.TODO(), bson.M{field: value})
	var result bson.M
	if err := ret.Decode(&result); err != nil {
		results.Mesg = err.Error()
	 	results.Code = mystruct.MyCodeErr
	 	return results, nil
	}
	return results, result
}

func (api Collections) See() (*mystruct.Retdate, []mystruct.ModelItem) {
	results := &mystruct.Retdate{"api-see", mystruct.MyCodeOk, "succeed"}

	ctx := context.TODO()
	res_cur, err := api.Find(ctx, bson.D{})
	if err != nil {
		results.Mesg = err.Error()
		results.Code = mystruct.MyCodeErr
		return results, nil
	}
	var result []mystruct.ModelItem
	if err := res_cur.All(ctx, &result); err != nil {
		results.Mesg = err.Error()
		results.Code = mystruct.MyCodeErr
		return results, nil
	}
	return results, result
}

func (api Collections) All(field, value string) (*mystruct.Retdate, []bson.M) {
	results := &mystruct.Retdate{"api-see", mystruct.MyCodeOk, "succeed"}

	ctx := context.TODO()
	res_cur, err := api.Find(ctx, bson.M{field: value})
	if err != nil {
		results.Mesg = err.Error()
		results.Code = mystruct.MyCodeErr
		return results, nil
	}
	var result []bson.M
	if err := res_cur.All(ctx, &result); err != nil {
		results.Mesg = err.Error()
		results.Code = mystruct.MyCodeErr
		return results, nil
	}
	return results, result
}

func (api Collections) Get(apiid string) (*mystruct.Retdate, *mystruct.ModelItem) {
	results := &mystruct.Retdate{"api-get", mystruct.MyCodeOk, "succeed"}

	ret := api.FindOne(context.TODO(), bson.M{"apiid": apiid})
	var result mystruct.ModelItem
	if err := ret.Decode(&result); err != nil {
		results.Mesg = err.Error()
	 	results.Code = mystruct.MyCodeErr
	 	return results, nil
	}
	return results, &result
}

func (api Collections) Set(apiid, field string, strVal interface{}) *mystruct.Retdate {
	results := &mystruct.Retdate{"api-set", mystruct.MyCodeOk, "succeed"}

	update := bson.D{{"$set", bson.D{bson.E{Key: field, Value: strVal}}}}
	ret, err := api.UpdateOne(context.TODO(), bson.M{"apiid": apiid}, update)
	results.Code = ret.ModifiedCount
	if err != nil {
	 	results.Mesg = err.Error()
	 	results.Code = mystruct.MyCodeErr
	 	return results
	}
	res := Get_Code(apiid)
	currentField := reflect.ValueOf(res.Body).Elem()
	fieldNames := strings.Split(field, ".")
	for _, fieldName := range fieldNames {
		fieldName = strings.ToUpper(fieldName[:1]) + fieldName[1:]
		currentField = currentField.FieldByName(fieldName)
		if !currentField.IsValid() {
			res.Cur.Drop(context.TODO())
			clientsMu.Lock()
			delete(MyMonDB.DataCur, apiid)
			clientsMu.Unlock()
			return results
		}
	}
	if currentField.CanSet() {
		switch currentField.Kind() {
			case reflect.Bool:
				currentField.SetBool(strVal.(bool))
			case reflect.String:
				currentField.SetString(strVal.(string))
			case reflect.Int64:
				currentField.SetInt(strVal.(int64))
		}
	}
	return results
}

func (api Collections) Del(apiid string) *mystruct.Retdate {
	results := &mystruct.Retdate{"api-del", mystruct.MyCodeOk, "succeed"}
    
    res := Get_Code(apiid)
	ret, err := api.DeleteOne(context.TODO(), bson.M{"apiid": apiid})
	results.Code = ret.DeletedCount
	if res != nil{
		err = res.Cur.Drop(context.TODO())
		if err != nil {
			results.Mesg = err.Error()
			results.Code = mystruct.MyCodeErr
		}
		clientsMu.Lock()
		delete(MyMonDB.DataCur, apiid)
    	clientsMu.Unlock()
	}
	if err != nil {
	 	results.Mesg = err.Error()
	}else{
		results.Mesg = fmt.Sprintf("%v", ret.DeletedCount)
	}
	return results
}

func (api Collections) Add(map_list mystruct.ModelItem) *mystruct.Retdate {
	results := &mystruct.Retdate{"api-add", mystruct.MyCodeOk, "succeed"}

	ret, _ := api.Get(map_list.Apiid)
	if ret.Code == mystruct.MyCodeOk {
		results.Code = mystruct.MyCodeErr
		results.Mesg = "API已经存在了<<<>>>"
		return results
	}else{
		ret, err := api.InsertOne(context.TODO(), map_list)
		if err != nil {
		 	results.Mesg = err.Error()
		 	results.Code = mystruct.MyCodeErr
		}else{
			oid, _ := ret.InsertedID.(primitive.ObjectID)
			results.Mesg = oid.Hex()
			clientsMu.Lock()
			body := Curs{
				Cur : MyMonDB.Database.Collection(map_list.Api),
				Body: &map_list,
			}
			MyMonDB.DataCur[map_list.Apiid] = body
			clientsMu.Unlock()
		}
		return results
	}
}